#include <SDL.h>

#include <string>

#ifdef _WIN32
   //define something for Windows (32-bit and 64-bit, this part is common)
   #ifdef _WIN64
      //define something for Windows (64-bit only)
   #else
      //define something for Windows (32-bit only)
   #endif
#elif __APPLE__
    #if TARGET_IPHONE_SIMULATOR
         // iOS Simulator
    #elif TARGET_OS_IPHONE
        // iOS device
    #elif TARGET_OS_MAC
        // Other kinds of Mac OS
    #else
        #error "Unknown Apple platform"
    #endif
#elif __ANDROID__
    // android
#elif __linux__
    // linux
#elif __unix__ // all unices not caught above
    // Unix
#elif defined(_POSIX_VERSION)
    // POSIX
#else
    #error "Unknown compiler"
#endif


const int SCREEN_WIDTH = 1920;
const int SCREEN_HEIGHT = 1080;


static SDL_Window *gWindow;
static SDL_Surface *gScreenSurface;
static SDL_Renderer *gRenderer;
static SDL_Texture* gTexture;

static bool Init(void);
static SDL_Surface *LoadSurface(std::string path);
static bool LoadMedia(void);
static void Close(void);


bool LoadMedia(void)
{
    SDL_Surface *sfHelloWorld = LoadSurface("bg.bmp");
    // ::SDL_BlitSurface(sfHelloWorld, NULL, gScreenSurface, NULL);
    gTexture = ::SDL_CreateTextureFromSurface(gRenderer, sfHelloWorld);
    ::SDL_FreeSurface(sfHelloWorld);

    // ::SDL_UpdateWindowSurface(gWindow);

    return true;
}


int main(int argc, char *argv[])
{
    if (! Init()) {
        return 1;
    }

    if (LoadMedia()) {
        bool running = true;

        while (running) {
            SDL_Event ev;

            if (::SDL_PollEvent(&ev)) { switch(ev.type) {
            case SDL_QUIT:
                running = false;
                break;
            case SDL_KEYDOWN:
                switch (ev.key.keysym.sym) {
                case SDLK_ESCAPE:
                    running = false;
                    break;
                case SDLK_UP:
                    fprintf(stderr, "keydown:up\n");
                    break;
                default:
                    fprintf(stderr, "keydown:unknown\n");
                    break;
                }
                break;
            case SDL_WINDOWEVENT:
                switch (ev.window.event) {
                case SDL_WINDOWEVENT_FOCUS_LOST:
                    ::SDL_RaiseWindow(gWindow);
                    ::SDL_SetWindowFullscreen(gWindow, SDL_WINDOW_FULLSCREEN);
                    break;
                default:
                    break;
                }
                break;
            default: break;
            }}

            // do renderer
            Uint32 lastime = ::SDL_GetTicks();

            ::SDL_RenderClear(gRenderer);
            ::SDL_RenderCopy(gRenderer, gTexture, NULL, NULL);

            // background
            SDL_Rect bgRect = {
                0, 0,
                SCREEN_WIDTH, SCREEN_HEIGHT,
            };
            ::SDL_SetRenderDrawColor(gRenderer, 0x00, 0x00, 0x00, 0xFF);
            ::SDL_RenderFillRect(gRenderer, &bgRect);

            SDL_Rect fillRect = {
                SCREEN_WIDTH / 4, SCREEN_HEIGHT / 4,
                SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2
            };
            ::SDL_SetRenderDrawColor(gRenderer, 0x00, 0x00, 0x00, 0xFF);
            ::SDL_RenderFillRect(gRenderer, &fillRect);

            SDL_Rect outlineRect = {
                SCREEN_WIDTH / 6, SCREEN_HEIGHT / 6,
                SCREEN_WIDTH * 2 / 3, SCREEN_HEIGHT * 2 / 3
            };
            ::SDL_SetRenderDrawColor(gRenderer, 0xFF, 0xFF, 0xFF, 0xFF);
            ::SDL_RenderDrawRect(gRenderer, &outlineRect);

            ::SDL_SetRenderDrawColor(gRenderer, 0x00, 0x00, 0xFF, 0xFF);
            ::SDL_RenderDrawLine(
                    gRenderer, 0,
                    SCREEN_HEIGHT / 2, SCREEN_WIDTH, SCREEN_HEIGHT / 2
            );

            // Draw vertical line of yellow dots
            ::SDL_SetRenderDrawColor(gRenderer, 0x00, 0x00, 0xFF, 0xFF);
            for (int i = 0; i < SCREEN_HEIGHT; i += 4) {
                ::SDL_RenderDrawPoint(gRenderer, SCREEN_WIDTH / 2, i);
            }

            ::SDL_RenderPresent(gRenderer); // 执行渲染

            Uint32 elaps = ::SDL_GetTicks() - lastime;
            if (elaps < 10) {
                ::SDL_Delay(10 - elaps);
            }
        }
    }

    Close();

    return 0;
}


bool Init(void)
{
    // Initialize SDL
    if (-1 == ::SDL_Init( SDL_INIT_VIDEO )) {
        fprintf(stderr, "SDL_Init() failed: %s\n", SDL_GetError());
        return false;
    }

    //Create window
    gWindow = ::SDL_CreateWindow(
        "SDL Tutorial", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
        SCREEN_WIDTH, SCREEN_HEIGHT,
        SDL_WINDOW_SHOWN | SDL_WINDOW_FULLSCREEN
    );
    if (NULL == gWindow) {
        fprintf(stderr, "SDL_CreateWindow() failed: %s\n", SDL_GetError());
        return false;
    }

    //Get window surface
    // gScreenSurface = ::SDL_GetWindowSurface(gWindow);
    // ::SDL_FillRect(
    //         gScreenSurface, NULL,
    //         ::SDL_MapRGB(gScreenSurface->format, 0x00, 0x00, 0x00)
    // );
    // ::SDL_UpdateWindowSurface(gWindow);

    // create renderer
    gRenderer = ::SDL_CreateRenderer(gWindow, -1, SDL_RENDERER_ACCELERATED);
    ::SDL_SetRenderDrawColor(gRenderer, 0xFF, 0xFF, 0xFF, 0xFF);

    return true;
}


void Close(void)
{
    ::SDL_DestroyRenderer(gRenderer);

    //Destroy window
    ::SDL_DestroyWindow(gWindow);
    gWindow = NULL;

    //Quit SDL subsystems
    ::SDL_Quit();

    return;
}


SDL_Surface *LoadSurface(std::string path)
{
    //Load image at specified path
    SDL_Surface *loadedSurface, *optmzSurface;

    loadedSurface = ::SDL_LoadBMP(path.c_str());
    if (NULL == loadedSurface) {
        fprintf(stderr, "SDL_LoadBMP() failed: %s\n", SDL_GetError());
        return NULL;
    }

    optmzSurface = loadedSurface;
    // optmzSurface = ::SDL_ConvertSurface(
    //         loadedSurface, gScreenSurface->format, 0
    // );
    // if (NULL == optmzSurface) {
    //     fprintf(stderr, "SDL_ConvertSurface() failed: %s\n", SDL_GetError());
    // }

    return optmzSurface;
}
